package com.fsserver.web.controller;

import com.fsserver.common.api.ApiResponse;
import com.fsserver.common.api.ResultCode;
import com.fsserver.core.dto.PaymentRequestDTO;
import com.fsserver.core.dto.RefundRequestDTO;
import com.fsserver.core.service.PaymentGatewayService;
import com.fsserver.core.vo.PaymentResponseVO;
import com.fsserver.core.vo.RequestNotification;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Positive;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

/**
 * 统一支付控制器
 * Unified Payment Controller
 *
 * @author fsserver
 */
@Slf4j
@Validated
@RestController
@RequestMapping("/unified/payment")
@Api(tags = "统一支付接口", description = "提供统一的支付、查询、退款等功能")
public class UnifiedPaymentController {

    @Autowired
    private PaymentGatewayService paymentGatewayService;

    /**
     * 统一创建支付
     * Unified Create Payment
     *
     * @param paymentRequestDTO 支付请求DTO
     * @param request HTTP请求
     * @return API响应
     */
    @PostMapping("/create")
    @ApiOperation(value = "统一创建支付", notes = "根据支付渠道和支付类型创建支付订单")
    public ApiResponse<PaymentResponseVO> createPayment(@Valid @RequestBody PaymentRequestDTO paymentRequestDTO, HttpServletRequest request) {
        try {
            // 设置用户IP
            paymentRequestDTO.setUserIp(getClientIp(request));
            
            // 调用统一支付接口
            PaymentResponseVO response = paymentGatewayService.createPayment(paymentRequestDTO);
            return ApiResponse.success(response);
        } catch (Exception e) {
            log.error("创建支付订单失败", e);
            return ApiResponse.error(ResultCode.SYSTEM_ERROR, "创建支付订单失败: " + e.getMessage());
        }
    }

    /**
     * 统一查询订单
     * Unified Query Order
     *
     * @param orderNo 订单号
     * @param paymentChannel 支付渠道
     * @return API响应
     */
    @GetMapping("/query")
    @ApiOperation(value = "统一查询订单", notes = "根据订单号和支付渠道查询订单")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "orderNo", value = "订单号", required = true, dataType = "String", paramType = "query"),
        @ApiImplicitParam(name = "paymentChannel", value = "支付渠道", required = true, dataType = "String", paramType = "query")
    })
    public ApiResponse<Map<String, Object>> queryOrder(
            @NotBlank(message = "订单号不能为空") @RequestParam String orderNo, 
            @NotBlank(message = "支付渠道不能为空") @RequestParam String paymentChannel) {
        try {
            Map<String, Object> result = paymentGatewayService.queryOrder(orderNo, paymentChannel);
            return ApiResponse.success(result);
        } catch (Exception e) {
            log.error("查询订单失败", e);
            return ApiResponse.error(ResultCode.SYSTEM_ERROR, "查询订单失败: " + e.getMessage());
        }
    }

    /**
     * 统一关闭订单
     * Unified Close Order
     *
     * @param orderNo 订单号
     * @param paymentChannel 支付渠道
     * @return API响应
     */
    @PostMapping("/close")
    @ApiOperation(value = "统一关闭订单", notes = "根据订单号和支付渠道关闭订单")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "orderNo", value = "订单号", required = true, dataType = "String", paramType = "query"),
        @ApiImplicitParam(name = "paymentChannel", value = "支付渠道", required = true, dataType = "String", paramType = "query")
    })
    public ApiResponse<Boolean> closeOrder(
            @NotBlank(message = "订单号不能为空") @RequestParam String orderNo, 
            @NotBlank(message = "支付渠道不能为空") @RequestParam String paymentChannel) {
        try {
            boolean result = paymentGatewayService.closeOrder(orderNo, paymentChannel);
            return ApiResponse.success(result);
        } catch (Exception e) {
            log.error("关闭订单失败", e);
            return ApiResponse.error(ResultCode.SYSTEM_ERROR, "关闭订单失败: " + e.getMessage());
        }
    }

    /**
     * 统一申请退款
     * Unified Apply Refund
     *
     * @param orderNo 订单号
     * @param refundNo 退款单号
     * @param totalAmount 订单总金额
     * @param refundAmount 退款金额
     * @param reason 退款原因
     * @param paymentChannel 支付渠道
     * @return API响应
     */
    @PostMapping("/refund")
    @ApiOperation(value = "统一申请退款", notes = "根据订单号和支付渠道申请退款")
    public ApiResponse<Map<String, Object>> refund(
            @NotBlank(message = "订单号不能为空") @RequestParam String orderNo,
            @NotBlank(message = "退款单号不能为空") @RequestParam String refundNo,
            @NotNull(message = "订单总金额不能为空") @Positive(message = "订单总金额必须大于0") @RequestParam Long totalAmount,
            @NotNull(message = "退款金额不能为空") @Positive(message = "退款金额必须大于0") @RequestParam Long refundAmount,
            @RequestParam(required = false) String reason,
            @NotBlank(message = "支付渠道不能为空") @RequestParam String paymentChannel) {
        try {
            Map<String, Object> result = paymentGatewayService.refund(orderNo, refundNo, totalAmount, refundAmount, reason, paymentChannel);
            return ApiResponse.success(result);
        } catch (Exception e) {
            log.error("申请退款失败", e);
            return ApiResponse.error(ResultCode.SYSTEM_ERROR, "申请退款失败: " + e.getMessage());
        }
    }

    /**
     * 统一申请退款（使用DTO）
     * Unified Apply Refund with DTO
     *
     * @param refundRequestDTO 退款请求DTO
     * @param paymentChannel 支付渠道
     * @return API响应
     */
    @PostMapping("/refund/dto")
    @ApiOperation(value = "统一申请退款(DTO)", notes = "使用退款DTO和支付渠道申请退款")
    public ApiResponse<Map<String, Object>> refundWithDTO(
            @Valid @RequestBody RefundRequestDTO refundRequestDTO,
            @NotBlank(message = "支付渠道不能为空") @RequestParam String paymentChannel) {
        try {
            Map<String, Object> result = paymentGatewayService.refund(refundRequestDTO, paymentChannel);
            return ApiResponse.success(result);
        } catch (Exception e) {
            log.error("申请退款失败", e);
            return ApiResponse.error(ResultCode.SYSTEM_ERROR, "申请退款失败: " + e.getMessage());
        }
    }

    /**
     * 统一查询退款
     * Unified Query Refund
     *
     * @param refundNo 退款单号
     * @param paymentChannel 支付渠道
     * @return API响应
     */
    @GetMapping("/refund/query")
    @ApiOperation(value = "统一查询退款", notes = "根据退款单号和支付渠道查询退款")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "refundNo", value = "退款单号", required = true, dataType = "String", paramType = "query"),
        @ApiImplicitParam(name = "paymentChannel", value = "支付渠道", required = true, dataType = "String", paramType = "query")
    })
    public ApiResponse<Map<String, Object>> queryRefund(
            @NotBlank(message = "退款单号不能为空") @RequestParam String refundNo, 
            @NotBlank(message = "支付渠道不能为空") @RequestParam String paymentChannel) {
        try {
            Map<String, Object> result = paymentGatewayService.queryRefund(refundNo, paymentChannel);
            return ApiResponse.success(result);
        } catch (Exception e) {
            log.error("查询退款失败", e);
            return ApiResponse.error(ResultCode.SYSTEM_ERROR, "查询退款失败: " + e.getMessage());
        }
    }

    /**
     * 处理支付通知
     * Handle Payment Notification
     *
     * @param paymentChannel 支付渠道
     * @param request HTTP请求
     * @return 处理结果
     */
    @PostMapping("/notify/payment/{paymentChannel}")
    @ApiOperation(value = "处理支付通知", notes = "处理支付结果通知")
    @ApiImplicitParam(name = "paymentChannel", value = "支付渠道", required = true, dataType = "String", paramType = "path")
    public String handlePaymentNotification(
            @NotBlank(message = "支付渠道不能为空") @PathVariable String paymentChannel, 
            HttpServletRequest request) {
        try {
            // 构建通知对象
            RequestNotification notification = buildNotification(request, paymentChannel);
            boolean result = paymentGatewayService.handlePaymentNotification(notification);
            
            // 根据支付渠道返回不同的成功标识
            if (result) {
                return PaymentGatewayService.CHANNEL_WECHAT.equals(paymentChannel) ? "SUCCESS" : "success";
            } else {
                return PaymentGatewayService.CHANNEL_WECHAT.equals(paymentChannel) ? "FAIL" : "fail";
            }
        } catch (Exception e) {
            log.error("处理{}支付通知失败", paymentChannel, e);
            return PaymentGatewayService.CHANNEL_WECHAT.equals(paymentChannel) ? "FAIL" : "fail";
        }
    }

    /**
     * 处理退款通知
     * Handle Refund Notification
     *
     * @param paymentChannel 支付渠道
     * @param request HTTP请求
     * @return 处理结果
     */
    @PostMapping("/notify/refund/{paymentChannel}")
    @ApiOperation(value = "处理退款通知", notes = "处理退款结果通知")
    @ApiImplicitParam(name = "paymentChannel", value = "支付渠道", required = true, dataType = "String", paramType = "path")
    public String handleRefundNotification(
            @NotBlank(message = "支付渠道不能为空") @PathVariable String paymentChannel, 
            HttpServletRequest request) {
        try {
            // 构建通知对象
            RequestNotification notification = buildNotification(request, paymentChannel);
            boolean result = paymentGatewayService.handleRefundNotification(notification);
            
            // 根据支付渠道返回不同的成功标识
            if (result) {
                return PaymentGatewayService.CHANNEL_WECHAT.equals(paymentChannel) ? "SUCCESS" : "success";
            } else {
                return PaymentGatewayService.CHANNEL_WECHAT.equals(paymentChannel) ? "FAIL" : "fail";
            }
        } catch (Exception e) {
            log.error("处理{}退款通知失败", paymentChannel, e);
            return PaymentGatewayService.CHANNEL_WECHAT.equals(paymentChannel) ? "FAIL" : "fail";
        }
    }

    /**
     * 构建通知对象
     * 
     * @param request HTTP请求
     * @param paymentType 支付类型
     * @return 通知对象
     * @throws Exception 异常
     */
    private RequestNotification buildNotification(HttpServletRequest request, String paymentType) throws Exception {
        RequestNotification notification = new RequestNotification();
        notification.setPaymentType(paymentType);
        notification.setRequestId(request.getHeader("Request-ID"));
        
        // 读取请求体
        StringBuilder sb = new StringBuilder();
        try (java.io.BufferedReader reader = request.getReader()) {
            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
        }
        notification.setBody(sb.toString());
        
        // 获取所有请求头
        Map<String, String> headers = new HashMap<>();
        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String name = headerNames.nextElement();
            headers.put(name, request.getHeader(name));
        }
        notification.setHeaders(headers);
        
        // 获取所有请求参数
        notification.setParameters(getRequestParams(request));
        
        return notification;
    }

    /**
     * 获取客户端IP
     * Get client IP
     *
     * @param request HTTP请求
     * @return 客户端IP
     */
    private String getClientIp(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

    /**
     * 获取请求参数
     * Get request parameters
     *
     * @param request HTTP请求
     * @return 请求参数
     */
    private Map<String, String> getRequestParams(HttpServletRequest request) {
        Map<String, String> params = new HashMap<>();
        Enumeration<String> parameterNames = request.getParameterNames();
        while (parameterNames.hasMoreElements()) {
            String name = parameterNames.nextElement();
            String value = request.getParameter(name);
            params.put(name, value);
        }
        return params;
    }
} 